package com.tjc.cloud.util.signature

import org.apache.commons.lang3.StringUtils
import org.bouncycastle.jcajce.provider.digest.Keccak
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import reactor.core.publisher.toMono
import java.io.File
import java.io.FileInputStream
import java.math.BigInteger
import java.nio.ByteBuffer
import java.nio.channels.FileChannel
import java.security.MessageDigest
import java.security.SecureRandom
import javax.crypto.Cipher
import javax.crypto.Mac
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.DESKeySpec
import javax.crypto.spec.SecretKeySpec


object DigestUtil {
    fun md5(bytes: ByteArray): String {
        val md5 = MessageDigest.getInstance("MD5")
        return bytes2hex(md5.digest(bytes))
    }
    fun  des(bytes: ByteArray, key: ByteArray): String {
        val algorithm = "DES"
        val keySpec = DESKeySpec(key)
        val factory=SecretKeyFactory.getInstance(algorithm)
        val secureKey = factory.generateSecret(keySpec)
        val cipher =Cipher.getInstance(algorithm)
        cipher.init(Cipher.ENCRYPT_MODE, secureKey, SecureRandom())
        return cipher.doFinal(bytes).base64Encode()
    }

    fun  desDecode(bytes: ByteArray, key: ByteArray): String {
        val algorithm = "DES"
        val keySpec = DESKeySpec(key)
        val factory=SecretKeyFactory.getInstance(algorithm)
        val secureKey = factory.generateSecret(keySpec)
        val cipher =Cipher.getInstance(algorithm)
        cipher.init(Cipher.DECRYPT_MODE, secureKey, SecureRandom())
        return cipher.doFinal(bytes).base64Encode()
    }
    fun des3(bytes: ByteArray, key: ByteArray): String {
        val algorithm = "DESede"
        val keySpec = SecretKeySpec(key, algorithm)
        val c1 = Cipher.getInstance(algorithm)
        c1.init(Cipher.ENCRYPT_MODE, keySpec)
        return c1.doFinal(bytes).base64Encode()
    }

    fun des3Decode(bytes: ByteArray, key: ByteArray): String {
        val algorithm = "DESede"
        val keySpec = SecretKeySpec(key, algorithm)
        val c1 = Cipher.getInstance(algorithm)
        c1.init(Cipher.DECRYPT_MODE, keySpec)
        return String(c1.doFinal(bytes))
    }

    fun keccak(bytes: ByteArray): ByteArray {
        val kecc = Keccak.Digest256()
        kecc.update(bytes, 0, bytes.size)
        return kecc.digest()

    }

    fun sha1(bytes: ByteArray): String {
        val md5 = MessageDigest.getInstance("SHA-1")
        return bytes2hex(md5.digest(bytes))
    }

    fun bytes2hex(bytes: ByteArray): String {
        val bigInt = BigInteger(1, bytes).toString(16)
        return StringUtils.leftPad(bigInt, 32, "0")
    }

    private const val HMAC_SHA1 = "HmacSHA1"
    fun hashHmac(bytes: ByteArray, key: ByteArray): String {

        // 根据给定的字节数组构造一个密钥。
        val signingKey = SecretKeySpec(key, HMAC_SHA1)
        val mac = Mac.getInstance(HMAC_SHA1)
        mac.init(signingKey)

        val rawHmac = mac.doFinal(bytes)
        return bytes2hex(rawHmac)
    }

}


fun ByteArray.keccak(): ByteArray = DigestUtil.keccak(this)
fun ByteArray.md5(): String = DigestUtil.md5(this)
fun ByteArray.sha1(): String = DigestUtil.sha1(this)
fun ByteArray.des3(key: ByteArray): String = DigestUtil.des3(this, key)
fun ByteArray.des(key: ByteArray): String = DigestUtil.des(this, key)
fun ByteArray.des3Decode(key: ByteArray): String = DigestUtil.des3Decode(this, key)
fun ByteArray.desDecode(key: ByteArray): String = DigestUtil.desDecode(this, key)

fun String.keccak(): ByteArray = this.toByteArray().keccak()
fun String.md5(): String = this.toByteArray().md5()
fun String.sha1(): String = this.toByteArray().sha1()
fun String.des3(key: ByteArray): String = this.toByteArray().des3(key)
fun String.des(key: ByteArray): String = this.toByteArray().des(key)
fun String.des3Decode(key: ByteArray): String = this.toByteArray().des3Decode(key)
fun String.desDecode(key: ByteArray): String = this.toByteArray().desDecode(key)

fun ByteArray.hashHmac(key: ByteArray): String = DigestUtil.hashHmac(this, key)

fun String.hashHmac(key: String): String = this.toByteArray().hashHmac(key.toByteArray())


fun File.toByteBuffer(): Mono<ByteBuffer> =
        this.toMono().flatMap { file ->
            FileInputStream(file).toMono().map {
                it.channel
            }.map { it.map(FileChannel.MapMode.READ_ONLY, 0, file.length()) }
        }

fun Flux<ByteBuffer>.md5() = this.reduce(MessageDigest.getInstance("MD5")) { digest, byteBuffer ->
    digest.update(byteBuffer)
    digest
}.map { it.digest() }
        .flatMapIterable {
            it.toList()
        }.flatMap {
            Flux.just(it.toInt() shr 4 and 0xf, it.toInt() and 0xf)
        }.map { Integer.toHexString(it).uppercase() }.reduce { a, s -> "$a$s" }

fun ByteBuffer.md5() = MessageDigest.getInstance("MD5").toMono().map { digest ->
    digest.update(this)
    digest.digest()
}.flatMapIterable {
    it.toList()
}.flatMap {
    Flux.just(it.toInt() shr 4 and 0xf, it.toInt() and 0xf)
}.map { Integer.toHexString(it).uppercase() }.reduce { a, s -> "$a$s" }

fun File.md5() = this.toByteBuffer().flatMap { it.md5() }


//fun main(args: Array<String>) {
////
////    val json="{\"orderNo\":\"\", \"merchantNo\":\"c10000213\"}"
////
////    val res=json.des3("J68yys6TYv5YNHTMtZrZnIa5".toByteArray())
////println(res)
////}


fun main(args: Array<String>) {
//
//    val data = "AdUTbJCMValsrKenJDvPl/Uk4XeGvRJ0dbkRXLlGfpTkGS/vDiCNQaMO1rg5yEwL3U0rcIpJ1Y0U92hb9z7OYZ8GiGvofzhF4+QDGC6CIO8s6QNMz5eLfQNRPLxPLxwl4WVCVGE2N9AiKpn2lruKGXDpMN4gmxwjfn1RbqxpiFCGSeI4iqsNgPmwYqO2jJvPJ0B9R0py2fXeIuE1pagBcL+QqfSR4pXNeA/1pYJYOi+gv8WErPwAWykycdFWNbzyIfI2j2Oy6scFm01GwkEh6vW6YobzxOXApyt7dNAdgOBRqhwVRXtceX4hBs8AS21nqidApR+6Co9WDzOdeYHtqOmXZyKVtZiuLa/1goAw1hr5foR0HPBVX0NnEGZRM+HnLLxxrUUKzZWkIdL/hm7EhEkhbbv9Wo7IIAv/YPKlkVtybp+sLJcO6M2rcvs2UAjTHzHQOpuzAp/oknwDjJj6lTcK16S0or2rcauyXnRcRf7Q3Y0mn1uJlj66tPG6QBcqMwgdBEqDBhTf/B1EcdL2bovjlSZS57+Sd+0LPIivcg0+6GqMggyp3PnxNij1km1WcDJe2r0Hz3DyxHEbT6vl3S3ehI6okNNMcqVwwP4Y3GM42/Madd4e7TafbmLJ4Fi9ySLs0NUReEkmEzHM8fFEJlF1YXwXgyzEV1cl+VGssG/GRwhEO0D9sX5jGeAKRMjcQToYCy6V9Kk9TyhrijgrhdIIBflynXJ1AMKWzDFMAFRR0S/niYzoonz2+NpQQhExQJVW+fmLCgbZbro01t24azWD6LevZSP+q+P3Y8J7gujlFujdnaim2Qg3316m2kVP6akowEVPLvIFNSP1odiSyJsiR8PPxjQvUAQZSrOOkJoKlBMyGLeZng2zWLIZj9B+dU93o4fjD5e+5jaG63szxYYYzC+oYqVvkSEUrh2faQBD4IpAHeivOlE7GzU9SHTXkLFQuFP0EXGX8tRSxIrMbImtSqJTjmGPHpSDvjHZXLb/KdTrNWK0DOPpeu5z2oouCak37LFnkozZnoRP1/pJlkCxNRU0JEoZINBoqp3qs9jLM0qig8ua7hV5tDJJSdfG/H7UffP6I5A6pxwhIp+OBJnFnUxJJwhgJ1//U65U1BvQAZzokr3kABwcHctj1aSNU1cLWSQ0zF8wn8EKTozlmOZZiKYIfHu+MS9Lg7YfL4Yjzzoo7Mo+1y81940rmyfOY+USXQQuYc+vC3afqQm8z5OpJBt3OAVBmB/yMj+Z8NI0gWkYPL8wpQQviHK7lY9p+1kW21xe9FXbQEx+S2AcA+K5zhxjvS+1UYKBIYnlUOSqXLN/NBZXTOK5zhxjvS+1+AAJYm82fVqtJ2vMUqk/mCUv+t55XfIeGLy14OK/+88Un/B5Jw5ew2vDowTrXtITHNRU/5r1M2BhWgLw9hYBh17nXQXRAGBgzFWB2l7atcUXEPYUK19lFhK5AnIkQll9ZlyP9HUHbHiaB4achLg6eY6rDQLNQfQJ"
//    println(data.base64DecodeBytes().des3Decode("X5YBd7H0KfPwKbV6KyybxX2n".toByteArray()))
}